int width = 600;
int height = 600;
Player player; //Even though we have a GameObject List we still keep track of the player in it's own variable
Camera cam;
ArrayList<GameObject> gameObjects; //Holds ALL GameObjects
ArrayList<Planet> planets; //Keeps track of the planets for gravity calculations
ArrayList<Ship> ships;
ArrayList<Particle> particles;
boolean gameOver;
int miniMapZoom = 50;
int planetCount;
int shipCount;
int enemyCount;
int particleCount;
int numGameObjects;
boolean antiAliasing = true;
int maxParticles = 500;
int score;
int maxEnemies;
boolean roundStarted;
boolean keyUP, keyDOWN, keyLEFT, keyRIGHT, keySPACE, keySHIFT, keyE, keyENTER, keyF;//true false variables which hold the state of each key (pressed/true and released/false), fixes keyrepeat problem

Enemy testEnemy;

void setup()
{
  size(width,height);
  frameRate(60);
  frame.setTitle("Force");
  if(antiAliasing)
    smooth();
  startGame();
}

void draw()
{

  applyInput();
  cam.update();
  background(0);
  checkPlayerStatus();
  checkEnemies();
  checkParticles();
  drawGameObjects();
  drawUI();
  enemyGenerator();
  if(gameOver)
  {
    text("GAME OVER", width/2 - 30, height/2);
    text("You scored " + score, width/2 - 35, (height/2) + 30);    
    text("Press SHIFT to restart.", width/2 - 55, (height/2) + 60);
  }
}

void addGameObject(GameObject go)
{
  gameObjects.add(go);
  if(go instanceof Planet)
  {
    planets.add((Planet)go);
    planetCount++;
  }
  else if(go instanceof Particle)
  {
    particles.add((Particle)go);
    particleCount++;
  }
  else if(go instanceof Ship)
  {
    ships.add((Ship)go);
    shipCount++;
    if(go instanceof Enemy)
    {
      enemyCount++;
    }
  }
  numGameObjects++;
}

void enemyGenerator()
{
  if(!roundStarted)
  {
    spawnRandomEnemy();
    
    if(enemyCount == maxEnemies)
      {
        roundStarted = true;
      }
  }

  else // roundStarted == true
  {
    if(enemyCount < 1)
    {
      roundStarted = false;
      maxEnemies++;
    }
  }
}

void checkPlayerStatus()
{
  if(!player.getAlive())
  {
    gameOver = true;
  }
}

//This could probably be moved to the enemies aswell
void checkEnemies()
{
  ArrayList<Enemy> deadEnemies = new ArrayList<Enemy>();
  for(Object o : gameObjects)
  {
    if(o instanceof Enemy)
    {
      Enemy anEnemy = (Enemy)o;
      if(!anEnemy.alive)
      {
         deadEnemies.add(anEnemy);
         enemyCount--;
      }
    }
  }
  for(Enemy e : deadEnemies)
  {
     int spawnX = (int)e.position.x;
     int spawnY = (int)e.position.y;
     //Loop to make things simpler
     for(int i=0; i < 9; i++){
       spawnHealth(spawnX,spawnY);
       spawnEnergy(spawnX,spawnY);
     }
     if(player.alive)
     {
       score = score + 10;
       if(e.getCrashed());
       {
         score = score - 5;
       }
     }
     removeGameObject(e);
  }
}

void checkParticles()
{
  ArrayList<Particle> deadParticles = new ArrayList<Particle>();
  for(Object o : gameObjects)
  {
    if(o instanceof Particle)
    {
      Particle aParticle = (Particle)o;
      if(!aParticle.alive)
      {
         deadParticles.add(aParticle);
      }
    }
  }
  for(Particle p : deadParticles)
  {
     removeGameObject(p);
  }
}

//Doesn't check if the object is actually in the list just yet
void removeGameObject(GameObject go)
{
  if(go instanceof Planet)
  {
    planets.remove(planets.indexOf(go));
    planetCount--;
  }
  else if(go instanceof Particle)
  {
    particles.remove(particles.indexOf(go));
    particleCount--;
  }
  else if(go instanceof Ship)
  {
    ships.remove(ships.indexOf(go));
    shipCount--;
  }
    gameObjects.remove(gameObjects.indexOf(go));
  numGameObjects--; 
}

 void startGame()
 {
  roundStarted = false;
  planetCount = 0;
  particleCount = 0;
  shipCount = 0;
  numGameObjects = 0;
  score = 0;
  enemyCount = 0;
  maxEnemies = 1;
  gameObjects = new ArrayList<GameObject>();
  planets = new ArrayList<Planet>();
  particles = new ArrayList<Particle>();
  ships = new ArrayList<Ship>();
  gameOver = false;
  player = new Player(500, 300, 50);
  cam = new Camera(player);
  addGameObject(player);
  //waint planetSize = (int)random(20,60);
  //addGameObject(new Planet((int)random(-3000,3000),(int)random(-3000,3000),(planetSize*100)^3, planetSize,color(random(50,255),random(50,255),random(50,255))));
  spawnPlanets();
 }

void spawnHealth(int x, int y)
{
    addGameObject(new Health(x, y, 25));
}

void spawnEnergy(int x, int y)
{
    addGameObject(new Energy(x, y, 25));
}

void spawnPlanets()
{
  for(int i = 0; i < 6; i++)
  {
    int planetSize = (int)random(20,60);
    addGameObject(new Planet((int)random(-3000,3000),(int)random(-3000,3000),(planetSize*100)^3, planetSize,color(random(50,255),random(50,255),random(50,255))));
  }
}

void spawnEnemy(int x, int y)
{
  addGameObject(new Enemy(x,y,50));
}

void spawnRandomEnemy()
{
  int randX, randY;
  randX = (int)random(player.position.x -1000, player.position.x + 1000);
  randY = (int)random(player.position.y -1000, player.position.y + 1000);
  
  if(randX > player.position.x)
    randX += 2*width;
  else
    randX -= 2*width; 
  
  if(randY > player.position.y)
    randY += 2*width;
  else
    randY -= 2*width;  
    
  spawnEnemy(randX,randY);
}
void drawGameObjects()
{
  for(int i=0; i<numGameObjects; i++)
  {
    GameObject go = gameObjects.get(i);
    if(go.drawn)
    {
      go.update();
      go.draw(cam);
    }
  }
}

void drawUI()
{
  drawHealthBar(220,50);
  drawEnergyBar(220,80);
  drawMinimap(50,50);
  //drawSpeedometer(50,220);
  drawScore(width - 100, 50);
}

void drawScore(int x, int y)
{
    stroke(20,200,20);
    text("Score : " + score,x,y);
}

void drawHealthBar(int x, int y)
{
  fill(180,70,70,50);
  stroke(180,70,70);
  rect(x,y,102,16);
  stroke(255,100,100);
  fill(255,100,100);
  rect(x+1,y+1,(int)((player.health / player.maxHealth)*100) ,14);//Health Bar
}

void drawSpeedometer(int x, int y)
{
  stroke(20,200,20);
  text("CurrentSpeed : " + sqrt(sq(player.velocity.x) + sq(player.velocity.y)),x,y);
  text("XSpeed : " + player.velocity.x,x,y + 16);
  text("YSpeed : " + player.velocity.y,x,y + 32);
}

void drawEnergyBar(int x, int y)
{
  fill(70,70,180,50);
  stroke(70,70,180);
  rect(x,y,102,16);
  fill(100,100,255);
  stroke(100,100,255);
  rect(x+1,y+1,(int)((player.energy / player.maxEnergy)*100),14);//Energy bar
}

void drawMinimap(int x, int y)
{
  fill(0,0,0,130);
  stroke(100);
  rect(x,y,140,140);
  
  stroke(0,255,0);
  fill(0,255,0);
  ellipse(x + 70,y+70,3,3);
  float ellipseX;
  float ellipseY;
  for(Object o : gameObjects)
  {
    if(o instanceof Planet)
    {
      Planet p = (Planet)o;
      fill(p.planetColor);
      stroke(p.planetColor);
      ellipseX = (x + 70) + (p.position.x - player.position.x)/ (miniMapZoom);
      ellipseY = (y + 70) + (p.position.y - player.position.y)/ (miniMapZoom);
      if(ellipseX > x && ellipseX < x + 140 && ellipseY > y && ellipseY < y + 140)
      {
      ellipse(ellipseX, ellipseY,2,2);
      }  
    }
  }
}
//INPUT CODE BELOW

void applyInput()
{
  if(keyUP)
  {
    player.accelerate();    
    player.setAccelerating(true);//these methods are for the purpose of displaying the thrusters properly
  }
  else
  {
    player.setAccelerating(false);
  }
  if(keyDOWN)
  {  
    player.decelerate();
    player.setDecelerating(true);
  }
  else
  {
    player.setDecelerating(false);
  }  
  if(keyLEFT)
  {
    player.turnLeft();
    player.setTurningLeft(true);
  }
  else
  {
    player.setTurningLeft(false);
  }
  if(keyRIGHT)
  {
    player.turnRight();  
    player.setTurningRight(true);
  }
  else
  {
    player.setTurningRight(false);
  }
  if(keyE)
  {
    //put the functionality in the keyPressed method
  }
  player.firing = keyF;
  if(keyF)
  {
    //player.startFiring();
  }
  if(!keyF)
  {
    //player.stopFiring();
  }
  if(keySPACE)
    player.enableGravity();
  else
    player.disableGravity();
    
  if(keySHIFT)
  {
    if(gameOver)
    {
      startGame();
    }
  }
}

void keyPressed() 
{
  if (key == CODED)
  {
    if(keyCode == SHIFT)
    {
        keySHIFT = true;
    }
  }
  if (key == 'E' || key == 'e') 
  {
      keyE = true;
      player.oppositeGravity();
  } 
  if (key == 'W' || key == 'w') 
  {
    keyUP = true;
  } 
  if (key == 'S' || key == 's')  
  {
    keyDOWN = true;  
  } 
  if (key == 'A' || key == 'a') 
  {
    keyLEFT = true;
  }
  if (key == 'D' || key == 'd') 
  {
    keyRIGHT = true;      
  }
  if (key == ' ') 
  {
    keySPACE = true;
  }  
    if (key == 'F' || key == 'f') 
  {
    keyF = true;
  }
}

void keyReleased() 
{
  if (key == CODED)
  {
    if(keyCode == SHIFT)
    {
      keySHIFT = false;
    }
  }
  if (key == 'E' || key == 'e') 
  {
      keyE = false;
  } 
  if (key == 'W' || key == 'w') 
  {
    keyUP = false;
  } 
  if (key == 'S' || key == 's')  
  {
    keyDOWN = false;  
  } 
  if (key == 'A' || key == 'a') 
  {
    keyLEFT = false;
  }
  if (key == 'D' || key == 'd') 
  {
    keyRIGHT = false;      
  }
  if (key == ' ') 
  {
    keySPACE = false;
  }
    if (key == 'F' || key == 'f') 
  {
    //player.fireBullet();
    keyF = false;
  }
}
